package ss.pku.jsa.type.io;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings({"unchecked","rawtypes"})
public class AnnotationStore {
	public static final String PARAM = "param:";
	public static final String RETURN = "ret:";
	public static final String THIS = "this:";
	public static final String METHOD = "method:";
	public static final String FIELD = "field:";
	
	Map<String, MethodQSig> methods = new HashMap();
	Map<String, FieldQSig> fields = new HashMap();

	public void put(QSig s) {
		if ((s instanceof FieldQSig)) {
			FieldQSig f = (FieldQSig) s;
			this.fields.put(f.sig, f);
		} else if ((s instanceof MethodQSig)) {
			MethodQSig m = (MethodQSig) s;
			this.methods.put(m.sig, m);
		} else {
			throw new IllegalArgumentException("unknown type: " + s.getClass());
		}
	}

	public FieldQSig getField(String sig) {
		return (FieldQSig) this.fields.get(sig);
	}

	public FieldQSig getField(String classTypeDesc, String name) {
		System.out.println("looking for " + classTypeDesc + "." + name);
		return getField(classTypeDesc + "." + name);
	}

	public MethodQSig getMethod(String sig) {
		return (MethodQSig) this.methods.get(sig);
	}

	public MethodQSig getMethod(String classTypeDesc, String name,
			String methodSig) {
		System.out.println("looking for " + classTypeDesc + "." + name
				+ methodSig);
		return getMethod(classTypeDesc + "." + name + methodSig);
	}

	public static void main(String[] args) {
		if (args.length != 1) {
			System.err.println("usage: AnnotationStore <Filename>");
			System.exit(1);
		}

		AnnotationStore store = null;
		AnnotationReader reader = null;
		try {
			reader = new AnnotationReader(new BufferedReader(new FileReader(
					args[0])));
			store = reader.readAll();
		} catch (IOException e) {
			System.err.println("IO exception on file: " + args[0] + "\n" + e);
			System.exit(1);
		}

		System.out.println(store);
	}

	public String toString() {
		StringBuilder ret = new StringBuilder();
		for (String s : this.methods.keySet()) {
			ret.append(s + "\n");
		}
		return ret.toString();
	}

	public String diff(AnnotationStore a) {
		StringBuilder ret = new StringBuilder();
		for (Map.Entry e : this.methods.entrySet()) {
			MethodQSig m1 = (MethodQSig) e.getValue();
			MethodQSig m2 = a.getMethod((String) e.getKey());
			if (m2 == null)
				ret.append("<<<<<<<<<<<<<<<<<\n" + m1
						+ ">>>>>>>>>>>>>>>\nMISSING\n==================\n");
			else if (!m1.equals(m2)) {
				ret.append("<<<<<<<<<<<<<<<<<\n" + m1 + ">>>>>>>>>>>>>>>\n"
						+ m2 + "\n==================\n");
			}
		}
		return ret.toString();
	}

	public String diffLostPrecision(AnnotationStore a) {
		StringBuilder ret = new StringBuilder();
		for (Map.Entry e : this.methods.entrySet()) {
			MethodQSig m1 = (MethodQSig) e.getValue();
			MethodQSig m2 = a.getMethod((String) e.getKey());
			if (m2 == null)
				ret.append("<<<<<<<<<<<<<<<<<\n" + m1
						+ ">>>>>>>>>>>>>>>\nMISSING\n==================\n");
			else if (!m2.asGoodAs(m1)) {
				ret.append("<<<<<<<<<<<<<<<<<\n" + m1 + ">>>>>>>>>>>>>>>\n"
						+ m2 + "\n==================\n");
			}
		}
		return ret.toString();
	}
}
